#include "aoe.h" 
#include <iostream>


AoE::AoE(EnhSim* simulator)
: Effect(simulator)
, additional_targets(0)
, additional_target_level(0)
, additional_target_percent(0.0f)
, aoe_start_time(0.0f)
, aoe_end_time(0.0f)
, aoeing(false)
{
	for(int i = 0; i < MAGIC_SCHOOL_SIZE; i++)
		magic_resistance[i] = 0;
}

AoE::~AoE(){
	delete[] rotation;
}

void AoE::setAdditionalTargets(const int& additional_targets, const f32& additional_target_percent, const int additional_target_level){
	if(additional_targets < 10)
		this->additional_targets = additional_targets; 
	else
		//cap the targets to 9 to avoid the aoe cap.
		this->additional_targets = 9;

	this->additional_target_percent = additional_target_percent / 100; 
	if(additional_target_level > TARGET_LEVEL || additional_target_level < 0)
		//default to 80:
		this->additional_target_level = 80;
	else
		this->additional_target_level = additional_target_level;
}

void AoE::calculateAoETime(const int64& simulation_duration){
	if(additional_targets == 0)
		return;
	//not 100% in aoe range?
	if(additional_target_percent < 1){
		//total time targets will be in range
		const int64 time_targets_in_range = simulation_duration * additional_target_percent;
		aoe_start_time = simulation_duration * (int64(random(100)) / 100.0f);
		//AoE end time overlapping sim duration?
		if((aoe_start_time + time_targets_in_range) > simulation_duration){
			aoe_end_time = simulation_duration;
			//pushing start time back
			aoe_start_time = aoe_end_time - time_targets_in_range;
		}
		else{
			aoe_end_time =  aoe_start_time + time_targets_in_range;
		}
	}
	else{
		aoe_start_time = 0.0f;
		aoe_end_time = simulation_duration;
	}
}

void AoE::event(const int& event_id){
	if(!aoeing){
		sim.addLowPrioEvent((aoe_end_time - aoe_start_time),this);
		aoeing = true;
	}
	else{
		aoeing = false;
	}
}

void AoE::setAoEEvent(){
	//No aoe time specified: early out
	if(aoe_start_time == aoe_end_time)
		return;

	//Start time is 0: start aoeing
	if(aoe_start_time == 0.0f){
		sim.addLowPrioEvent((aoe_end_time - aoe_start_time),this);
		aoeing = true;
	}
	//add event: when the aoe time starts
	else{
		sim.addLowPrioEvent(aoe_start_time,this);
	}
}

void AoE::calculateDamageReduction(){
	//crit reduction for attacks
	white_crit_reduction = BASE_CRIT_REDUCTION + (additional_target_level - ATTACKER_LEVEL) * 60;
	yellow_crit_reduction = (additional_target_level - ATTACKER_LEVEL) * 60;

	//spell reduction
	int effective_resistance = (std::max<int>((additional_target_level - ATTACKER_LEVEL) * 5, 0) - std::min<int>(0/*spell penetration*/, 0));
	magic_resistance[ARCANE] = 1.0f - (effective_resistance / (ATTACKER_LEVEL * 5.0f)) * 75.0f / 100.0f;
	magic_resistance[FIRE] = 1.0f - (effective_resistance / (ATTACKER_LEVEL * 5.0f)) * 75.0f / 100.0f;
	magic_resistance[FROST] = 1.0f - (effective_resistance / (ATTACKER_LEVEL * 5.0f)) * 75.0f / 100.0f;
	magic_resistance[NATURE] = 1.0f - (effective_resistance / (ATTACKER_LEVEL * 5.0f)) * 75.0f / 100.0f;
	magic_resistance[SHADOW] = 1.0f - (effective_resistance / (ATTACKER_LEVEL * 5.0f)) * 75.0f / 100.0f;
}

void AoE::setRotationCount(const int& count){
	rotation = new Castable*[count];
	rotation_count = count;
}

void AoE::setRotation(const int& index, Castable* cast){
	rotation[index] = cast;
}

int AoE::getAdditiontalTargets(){
	return additional_targets;
}

int AoE::getRotationCount(){
	return rotation_count;
}

Castable* AoE::getRotation(const int& index){
	return rotation[index];
}

bool AoE::getAoeing(){
	return aoeing;
}

f32& AoE::getMagicResistance(const int& index){
	return magic_resistance[index];
}